Android 上的 Kotlin 协程(Coroutines)

您所在的位置:网站首页 java调用kotlin suspend Android 上的 Kotlin 协程(Coroutines)

Android 上的 Kotlin 协程(Coroutines)

2023-07-06 16:31| 来源: 网络整理| 查看: 265

一、协程的概念

协程(Coroutines)是一种并发设计模式,可以在 Android 平台上使用它来简化异步执行的代码。 协程是在版本 1.3 中添加到 Kotlin 的,它基于来自其他语言的既定概念。

在 Android 上,协程有助于管理长时间运行的任务.

二、协程的特点

协程是在 Android 上进行 异步编程 的推荐解决方案。值得关注的特点包括: (1)轻量:可以在单个线程上运行多个协程, 因为协程支持挂起,不会使正在运行协程的线程阻塞。 挂起比阻塞 节省内存 ,且支持多个 并行操作。 (2)内存泄漏更少:使用结构化并发机制 在 一个作用域 内执行 多项操作。 (3)内置取消支持:取消操作 会自动 在运行中的 整个协程层次结构 内传播。 (4)Jetpack 集成:许多 Jetpack 库 都包含提供全面 协程支持 的 扩展。 某些库还提供自己的协程作用域,可供用于结构化并发。

三、示例 1. 示例概览

实现:发出网络请求 并 将结果返回到 主线程,然后应用可以在 主线程上 向用户 显示结果。

具体而言,ViewModel 架构组件 会在 主线程 上调用 代码库层,以触发 网络请求。 会介绍多种使用 协程 确保 主线程畅通的解决方案:

withContext()函数 转移线程 , 并 结合 suspend( 挂起)关键字 强制从协程里 调用. viewModelScope.launch 启动新协程

ViewModel 包含一组可直接 与协程配合 使用的 KTX 扩展。这些扩展是 lifecycle-viewmodel-ktx 库.

2. 依赖项信息

应用的 build.gradle

dependencies { implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9") } 3. 具体类 3.1 结果类 sealed class Result { data class Success(val data: T) : Result() data class Error(val exception: Exception) : Result() } 3.2 存储库类,触发 网络请求. class LoginRepository(private val responseParser: LoginResponseParser) { private const val loginUrl = "https://example.com/login" suspend fun makeLoginRequest( jsonBody: String ): Result { // Move the execution of the coroutine to the I/O dispatcher return withContext(Dispatchers.IO) { // Blocking network request code val url = URL(loginUrl) (url.openConnection() as? HttpURLConnection)?.run { requestMethod = "POST" setRequestProperty("Content-Type", "application/json; utf-8") setRequestProperty("Accept", "application/json") doOutput = true outputStream.write(jsonBody.toByteArray()) return Result.Success(responseParser.parse(inputStream)) } return Result.Error(Exception("Cannot open HttpURLConnection")) } } }

分析: (1) 使用 withContext()函数将 协程的执行操作 移至其他线程( I/O 线程) (2) suspend 关键字进行标记函数,强制从协程内调用它.

3.3 登录ViewModel, 在主线程调用 存储库 类. class LoginViewModel( private val loginRepository: LoginRepository ): ViewModel() { fun login(username: String, token: String) { // Create a new coroutine on the UI thread viewModelScope.launch { val jsonBody = "{ username: \"$username\", token: \"$token\"}" // Make the network call and suspend execution until it finishes val result = loginRepository.makeLoginRequest(jsonBody) // Display result of the network request to the user when (result) { is Result.Success -> // Happy path else -> // Show error in UI } } } }

分析: (1) 应用从主线程上的 View 层调用 login() 函数。 (2) launch 在主线程上创建新协程,然后协程开始执行。 (3) 在协程内,调用 loginRepository.makeLoginRequest() 现在会挂起协程的进一步执行操作, 直至 makeLoginRequest() 中的 withContext 块结束运行。 (4) withContext 块结束运行后, login() 中的协程在主线程上恢复执行操作, 并返回网络请求的结果。 (5) 处理 Repository 层可能抛出的异常, 使用的是 try-catch 块

4. 一些总结:

(1) viewModelScope.launch 里面调用 使用suspend 声明 且 使用了withConext()(转移到其它调度程序的某个线程的)函数.

(2) viewModelScope 与界面生命周期绑定(默认在主调度程序 Dispatchers.Main), 因此,当用户离开屏幕时,此协程启动的操作将自动取消。

(3) 当协程调用标记为 suspend 的函数时, 它不会像常规函数调用一样在函数返回之前进行阻塞,而是挂起执行, 直到结果就绪为止,然后从上次停止的位置恢复并使用返回的结果。 当它挂起并等待结果时,它会取消阻塞正在运行它的线程,以便其他函数或协程可以运行。 (Kotlin编译器会把suspend 声明的函数,转换成callback形式的代码)

(4) 重要提示:suspend 关键字不指定运行代码的线程。挂起函数可以在后台线程或主线程上运行。

(5) 一个协程里可以运行多个线程



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3